﻿using ARPaintServer.Model.Hub;
using Microsoft.AspNetCore.SignalR;

namespace ARPaintServer.Hubs
{
	public class GameHub:Hub
	{
		private static List<GroupInfo> _groupInfos=new();
		private static List<UserInfo> _userInfos = new();
		private readonly ILogger<GameHub> _logger;

		#region 
		public GameHub(ILogger<GameHub> logger)
		{
			_logger = logger;
		}

		public override Task OnConnectedAsync()
		{			
			_userInfos.Add(new() { ConnectionId = Context.ConnectionId });
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:加入了一个新用户{Context.ConnectionId}");

			return Task.CompletedTask;
		}

		public override async Task OnDisconnectedAsync(Exception? exception)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			_userInfos.Remove(userInfo);
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:用户{Context.ConnectionId}离开了");
			if (!string.IsNullOrEmpty(userInfo.GroupId))
			{
				GroupInfo groupInfo = _groupInfos.Find(groupInfo => groupInfo.Id == userInfo.GroupId);				
				groupInfo.UserInfos.Remove(userInfo);
				
				if (groupInfo.UserInfos.Count == 0)
				{
					_logger.LogInformation($"{DateTimeOffset.UtcNow}:{groupInfo.Name}组所有玩家都离开了，删除组");
					_groupInfos.Remove(groupInfo);
				}
				else
				{
					await Clients.Group(groupInfo.Name).SendAsync("PlayerLeaveGroup", groupInfo.UserInfos);
				}

			}

			await base.OnDisconnectedAsync(exception);

		}

		#endregion


		#region --客户端调用--

		/// <summary>
		/// 加入组
		/// </summary>
		/// <param name="groupName"></param>
		/// <returns></returns>
		public async Task<ReciveMessage<GroupInfo>> AddToGroupByName(string groupName)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			GroupInfo groupInfo= _groupInfos.Find(groupinfo => groupinfo.Name == groupName);
			ReciveMessage<GroupInfo> result;

			if (groupInfo == null)
			{
				groupInfo = new()
				{ 
					Id = Guid.NewGuid().ToString(),
					State = GroupInfo.GameState.Linking,
					Name = groupName,
					UserInfos = new(),
					ArtworkIds = new()
				};
                _logger.LogInformation($"{DateTimeOffset.UtcNow}:<创建了一个新的组: <{groupName}>");
                _groupInfos.Add(groupInfo);
			}
			else
			{
				if (groupInfo.State != GroupInfo.GameState.Paint)
				{
					result = new()
					{
						Data = groupInfo,
						State = false,
					};				
				}
			}

			
			await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
			userInfo.GroupId = groupInfo.Id;
			groupInfo.UserInfos.Add(userInfo);
			

			await Clients.Group(groupName).SendAsync("NewPlayerEnterGroup",groupInfo.UserInfos);
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:<{Context.ConnectionId}>加入了 <{groupName}>");
	
			result = new()
			{
				Data = groupInfo,
			};

			return result;

		}

		/// <summary>
		/// 设置用户名
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public Task<ReciveMessage<UserInfo>> SetName(string name)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			userInfo.Name = name;
			ReciveMessage<UserInfo> result = new() { Data = userInfo };
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:<{Context.ConnectionId}>确定用户名为<{name}>");
			return Task.FromResult(result);
		}

		/// <summary>
		/// 选择绘画主题
		/// </summary>
		/// <param name="theme"></param>
		/// <returns></returns>
		public Task<ReciveMessage<UserInfo>> SelectTheme(string theme)
		{			
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			userInfo.Theme=theme;
			
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:<{Context.ConnectionId}>选择了<{theme}>作为作品主题");
			ReciveMessage<UserInfo> result = new() { Data = userInfo };
			return Task.FromResult(result);
		}

		/// <summary>
		/// 设置准备状态
		/// </summary>
		/// <param name="isReady"></param>
		/// <returns></returns>
		public async Task<ReciveMessage<UserInfo>> SetReadyState(bool isReady)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			userInfo.IsReady = isReady;

			if(isReady)
			{
				GroupInfo groupInfo = _groupInfos.TakeWhile(groupInfo => groupInfo.Id == userInfo.GroupId).First();
				if (groupInfo.UserInfos.All(userInfo => userInfo.IsReady))
				{
				 await GameStateToPlay(groupInfo);
				}
			}

			ReciveMessage<UserInfo> result = new() { Data = userInfo };
			return result;
		}

		/// <summary>
		/// 设置完成作品
		/// </summary>
		/// <param name="artworkUID"></param>
		/// <returns></returns>
		public async Task SetFinishArtworkAsync(string artworkUID)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			userInfo.ArtworkUid = artworkUID;
			GroupInfo groupInfo = _groupInfos.TakeWhile(groupInfo => groupInfo.Id == userInfo.GroupId).First();

			Clients.Group(groupInfo.Name).SendAsync("FinishArtwork",groupInfo.UserInfos);
			if (groupInfo.UserInfos.All(userInfo => !string.IsNullOrEmpty( userInfo.ArtworkUid)))
			{
				await GameStateToComment(groupInfo);
			}
		}

		/// <summary>
		/// 设置完成评论
		/// </summary>
		/// <param name="commentInfos"></param>
		public void SetFinishComment(ReciveMessage<List<CommentInfo>> commentInfos)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			GroupInfo groupInfo = _groupInfos.TakeWhile(groupInfo => groupInfo.Id == userInfo.GroupId).First();

			foreach (var item in commentInfos.Data)
			{
				userInfo.GuessCorrect += item.GuessNumber;

				UserInfo beCommentUser = groupInfo.UserInfos.Find(userInfo => userInfo.ConnectionId == item.AuthorUID);
				beCommentUser.BeGuessCorrect += item.GuessNumber;
				beCommentUser.ArtworkScore += item.Score;
			}
			userInfo.IsReady = true;

			if (groupInfo.UserInfos.All(userInfo => userInfo.IsReady))
			{
				GameStateToSettle(groupInfo);
			}
		}

		/// <summary>
		/// 发送信息
		/// </summary>
		/// <param name="message"></param>
		public void SendMessageInGroup(string message)
		{
			UserInfo userInfo = _userInfos.Find(userinfo => userinfo.ConnectionId == Context.ConnectionId);
			GroupInfo groupInfo = _groupInfos.TakeWhile(groupInfo => groupInfo.Id == userInfo.GroupId).First();

			Clients.Group(groupInfo.Name).SendAsync("GetGroupMessage", userInfo.Name, message);
		}

		#endregion


		#region ——服务器调用客户端——

		/// <summary>
		/// 修改游戏状态到游玩(绘画)状态
		/// </summary>
		/// <param name="groupInfo"></param>
		/// <returns></returns>
		private async Task GameStateToPlay(GroupInfo groupInfo)
		{
			groupInfo.State = GroupInfo.GameState.Paint;
			await Clients.Group(groupInfo.Name).SendAsync("ToPlayState");
			groupInfo.UserInfos.ForEach(userInfo => { userInfo.IsReady = false; });
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:<{groupInfo.Name}>组完成选题,开始游戏");
		}

		/// <summary>
		/// 修改游戏状态到评价状态
		/// </summary>
		/// <param name="groupInfo"></param>
		/// <returns></returns>
		private async Task GameStateToComment(GroupInfo groupInfo)
		{
			groupInfo.State = GroupInfo.GameState.Comment;
			await Clients.Group(groupInfo.Name).SendAsync("ToCommentState");
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:<{groupInfo.Name}>组完成创作,开始猜测和评价");
		}

		/// <summary>
		/// 修改游戏状态到评价状态
		/// </summary>
		/// <param name="groupInfo"></param>
		/// <returns></returns>
		private async Task GameStateToSettle(GroupInfo groupInfo)
		{
			groupInfo.State = GroupInfo.GameState.Result;
			await Clients.Group(groupInfo.Name).SendAsync("ToSettleState",groupInfo.UserInfos);
			_logger.LogInformation($"{DateTimeOffset.UtcNow}:<{groupInfo.Name}>组完成评价,进入结算界面");
		}

		#endregion
	}
}
